﻿using System;

namespace WikeSoft.Core.Exception
{
    /// <summary>
    /// 作用： 
    /// 该异常相对特殊，当业务方法中因为业务规则，不符合要求等情况，需要中止业务执行。
    /// 并且，又需要给予用户相对友好的提示信息，这类情况下，可以考虑 抛出该类异常，指定友好的用户提示信息。
    /// 这类异常，最终会在 宿主（mvc/webapi...） 的异常处理中，进行处理，友好的给予用户呈现。并且 !!通常不会进行 日志记录!! ，因为作为对用户的引导，说明是我们预知到的情况，
    /// 相当于我们已经 handle 了，而且也引导（告知到）用户了，所以本质上不应该当作异常对待，所以不会记录日志。
    /// 
    /// 日志，通常记录的是 unhandler 意义上的异常。目的是为了进行不可控问题的追踪分析
    /// 
    /// 也就是说： 只有我们主动想要进行 用户友好提示 的时候，才应该考虑使用该异常作为代码流中止同时又给予用户引导。
    /// 
    /// !!!注!!!
    /// 并不是所有异常都应该使用该类型进行抛出，正常的异常处理还是走正常的异常处理。仅限于需要从业务方法上友好提示用户的情况。
    /// 比如，如果一个方法的参与为 null，但是该方法又需要保证参与有效，就应该使用 ArguementNullException。
    /// 如果这个参数不为空，但是通过这个参数查询出来的 数据记录为空（比如合同），然后接下里的代码中依赖对这个 合同记录进行处理。
    /// 那么有两种方式： 从方法语义上支持 合同 为空的处理（比如跳过等等）。
    ///                如果方法语义上不支持，必须要有 合同 才能进行相关处理，这时候可以考虑抛出该异常，提示用户信息为： 找不到用户合同信息
    /// 
    /// 
    /// 不好的例子：
    /// 1. 对一大段代码进行 try catch， 然后把所有异常类型，再封装成 TipInfoException 进行抛出。
    ///     
    ///     像这种类型，不满足上面的规则，它不是我们主动想进行的引导，而只是为了把问题对用户隐藏。这种情况就去掉 try catch，交给框架全局的异常出来来进行。
    ///     全局异常处理，会记录下这类 未捕获 的异常，然后进行 日志记录 等，最后有好的给予用户呈现。 
    /// </summary>
    [Serializable]
    public class TipInfoException : System.Exception
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="tipMsg">是用于显示给用户看的首要信息</param>
        /// <param name="errorInfo">所有需要附加给用户知晓的，附加给调用方进行处理的额外信息，通常通过约定进行内容获取的处理</param>
        public TipInfoException(string tipMsg, object errorInfo = null) : base(tipMsg)
        {
            this.InitErrorInfo(errorInfo);
        }

        public TipInfoException(string tipMsg, System.Exception innerException, object errorInfo = null) : base(tipMsg, innerException)
        {
            this.InitErrorInfo(errorInfo);
        }

        private void InitErrorInfo(object errorInfo)
        {
            Data["TipForUI"] = errorInfo;
        }
    }
}
